const mongoose = require("mongoose");
const Sales = require("../models/Sales");
const Warehouse = require("../models/warehouseModel");
const Customer = require("../models/customerDataModel");
const Item = require("../models/itemModel");
const PaymentType = require("../models/paymentTypeModel");
const Tax = require("../models/taxModel");
const Account = require("../models/accountModel");

function generateRandomCode(prefix = "PMT/2025/") {
  const randomNum = Math.floor(Math.random() * 9000) + 1000; // 4-digit random
  return prefix + randomNum;
}

// Create a new sale
exports.createSale = async (req, res) => {
  try {
    const {
      warehouse,
      customer,
      saleCode,
      saleDate,
      referenceNo,
      items,
      otherCharges,
      discountCouponCode,
      couponType,
      couponValue,
      discountOnBill,
      note,
      payments,
      status,
    } = req.body;

    // Basic validations
    if (!warehouse || !customer || !saleCode || !items?.length) {
      return res.status(400).json({ message: "Missing required fields!" });
    }

    // Validate warehouse
    const warehouseExists = await Warehouse.findById(warehouse);
    if (!warehouseExists) {
      return res.status(404).json({ message: "Warehouse not found!" });
    }

    // Validate customer
    const customerExists = await Customer.findById(customer);
    if (!customerExists) {
      return res.status(404).json({ message: "Customer not found!" });
    }

    // Build items array
    let totalSubtotal = 0;
    let validItems = [];

    for (const it of items) {
      const itemDoc = await Item.findById(it.item);
      if (!itemDoc) {
        return res.status(404).json({ message: `Item not found: ${it.item}` });
      }

      // Validate optional tax
      if (it.tax) {
        const taxDoc = await Tax.findById(it.tax);
        if (!taxDoc) {
          return res.status(404).json({ message: `Tax not found: ${it.tax}` });
        }
      }

      const lineSubtotal =
        (it.unitPrice - (it.discount || 0) + (it.taxAmount || 0)) *
        it.quantity;

      totalSubtotal += lineSubtotal;

      validItems.push({
        item: itemDoc._id,
        quantity: it.quantity,
        unitPrice: it.unitPrice,
        discount: it.discount || 0,
        tax: it.tax || null,
        taxAmount: it.taxAmount || 0,
        subtotal: lineSubtotal,
      });
    }

    let grandTotal = totalSubtotal + (otherCharges || 0);

    if (couponType === "percentage") {
      grandTotal -= (grandTotal * (couponValue || 0)) / 100;
    } else if (couponType === "value") {
      grandTotal -= couponValue || 0;
    }

    if (discountOnBill) {
      grandTotal -= discountOnBill;
    }

    
    let validPayments = [];
    if (payments && payments.length) {
      for (const p of payments) {
        const paymentTypeDoc = await PaymentType.findById(p.paymentType);
        if (!paymentTypeDoc) {
          return res
            .status(404)
            .json({ message: `Payment type not found: ${p.paymentType}` });
        }

        let paymentCode = p.paymentCode;
        if (!paymentCode) {
          paymentCode = generateRandomCode("PMT/2025/"); 
        }

        validPayments.push({
          paymentCode,
          amount: p.amount,
          paymentType: paymentTypeDoc._id,
          account: p.account || null,
          paymentNote: p.paymentNote || "",
          paymentDate: p.paymentDate || Date.now(), 
        });
      }
    }


    let createdBy = null;
    let createdByModel = null;
    if (req.user && req.user.id) {
      createdBy = req.user.id;
      createdByModel =
        req.user.role.toLowerCase() === "admin" ? "Admin" : "User";
    }

   
    const newSale = new Sales({
      warehouse,
      customer,
      createdBy,
      createdByModel,
      saleCode,
      saleDate,
      referenceNo,
      items: validItems,
      otherCharges: otherCharges || 0,
      discountCouponCode: discountCouponCode || "",
      couponType: couponType || "",
      couponValue: couponValue || 0,
      discountOnBill: discountOnBill || 0,
      note: note || "",
      payments: validPayments,
      subtotal: totalSubtotal,
      grandTotal,
      status: status || "Draft",
    });

    await newSale.save();
    res.status(201).json({
      message: "Sale created successfully!",
      sale: newSale,
    });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};


exports.getAllSales = async (req, res) => {
  try {
    
    const totalInvoices = await Sales.countDocuments({});
    const invoiceAmountAgg = await Sales.aggregate([
      { $group: { _id: null, total: { $sum: "$grandTotal" } } },
    ]);
    const totalInvoiceAmount = invoiceAmountAgg.length
      ? invoiceAmountAgg[0].total
      : 0;

    const paymentsAgg = await Sales.aggregate([
      { $unwind: "$payments" },
      { $group: { _id: null, total: { $sum: "$payments.amount" } } },
    ]);
    const totalReceivedAmount = paymentsAgg.length ? paymentsAgg[0].total : 0;

    const totalSalesDue = totalInvoiceAmount - totalReceivedAmount;

    
    const sales = await Sales.find()
      .populate("warehouse customer payments.paymentType")
      .populate({ path: "items.item" })
      .populate({ path: "items.tax" })
      
      .populate("createdBy", "name FirstName LastName email");

    
    const processedSales = sales.map((sale) => {
      let creatorName = "";
      if (sale.createdBy) {
        if (sale.createdByModel === "Admin" && sale.createdBy.name) {
          creatorName = sale.createdBy.name;
        } else if (sale.createdBy.FirstName && sale.createdBy.LastName) {
          creatorName = `${sale.createdBy.FirstName} ${sale.createdBy.LastName}`;
        }
      }
      return {
        ...sale.toObject(),
        creatorName,
      };
    });

    res.status(200).json({
      summary: {
        totalInvoices,
        totalInvoiceAmount,
        totalReceivedAmount,
        totalSalesDue,
      },
      sales: processedSales,
    });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};


exports.getSalesPayments = async (req, res) => {
  try {
    const { paymentType, paymentStatus } = req.query;

    
    const pipeline = [
      
      { $unwind: "$payments" },

      
      {
        $match: {
          ...(paymentType
            ? { "payments.paymentType": new mongoose.Types.ObjectId(paymentType) }
            : {}),
          ...(paymentStatus ? { "payments.paymentStatus": paymentStatus } : {}),
        },
      },

      
      {
        $lookup: {
          from: "paymenttypes",
          localField: "payments.paymentType",
          foreignField: "_id",
          as: "paymentTypeData",
        },
      },
      {
        $addFields: {
          "payments.paymentTypeData": {
            $arrayElemAt: ["$paymentTypeData", 0],
          },
        },
      },

      
      {
        $lookup: {
          from: "customerdatas", 
          localField: "customer",
          foreignField: "_id",
          as: "customerDoc",
        },
      },
      {
        $addFields: {
          customerDoc: { $arrayElemAt: ["$customerDoc", 0] },
        },
      },

      
      {
        $lookup: {
          from: "users",
          localField: "createdBy",
          foreignField: "_id",
          as: "createdByUser",
        },
      },
      {
        $lookup: {
          from: "admins",
          localField: "createdBy",
          foreignField: "_id",
          as: "createdByAdmin",
        },
      },
      {
        $addFields: {
          createdByDoc: {
            $cond: {
              if: { $gt: [{ $size: "$createdByUser" }, 0] },
              then: { $arrayElemAt: ["$createdByUser", 0] },
              else: { $arrayElemAt: ["$createdByAdmin", 0] },
            },
          },
        },
      },
    ];

   
    const payments = await Sales.aggregate(pipeline);

    
    const formatted = payments.map((doc) => {
     
      let creatorName = "";
      if (doc.createdByDoc) {
        if (
          doc.createdByModel === "Admin" &&
          doc.createdByDoc.name &&
          doc.createdByDoc.name !== ""
        ) {
          creatorName = doc.createdByDoc.name;
        } else if (
          doc.createdByDoc.FirstName &&
          doc.createdByDoc.LastName &&
          (doc.createdByDoc.FirstName !== "" || doc.createdByDoc.LastName !== "")
        ) {
          creatorName = `${doc.createdByDoc.FirstName} ${doc.createdByDoc.LastName}`;
        }
      }

      return {
        saleId: doc._id,
        saleCode: doc.saleCode,
        
        customer: doc.customerDoc?.customerName || "Unknown",
        // Payment details
        paymentCode: doc.payments.paymentCode || "N/A",
        paymentDate: doc.payments.paymentDate, 
        paymentType:
          doc.payments.paymentTypeData?.paymentTypeName || "Unknown",
        paymentAmount: doc.payments.amount,
        paymentNote: doc.payments.paymentNote,
        creatorName,
      };
    });

    res.status(200).json(formatted);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};

// Get single sale
exports.getSaleById = async (req, res) => {
  try {
    const sale = await Sales.findById(req.params.id)
      .populate("warehouse customer payments.paymentType")
      .populate({ path: "items.item" })
      .populate({ path: "items.tax", model: "Tax" })
      .populate("createdBy", "name FirstName LastName email"); // dynamic reference

    if (!sale) {
      return res.status(404).json({ message: "Sale not found!" });
    }

    // Compute creatorName
    let creatorName = "";
    if (sale.createdBy) {
      if (sale.createdByModel === "Admin" && sale.createdBy.name) {
        creatorName = sale.createdBy.name;
      } else if (sale.createdBy.FirstName && sale.createdBy.LastName) {
        creatorName = `${sale.createdBy.FirstName} ${sale.createdBy.LastName}`;
      }
    }

    const processedSale = { ...sale.toObject(), creatorName };
    res.status(200).json(processedSale);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};

// Update sale
exports.updateSale = async (req, res) => {
  try {
    const { id } = req.params;

    const updatedSale = await Sales.findByIdAndUpdate(id, req.body, {
      new: true,
    })
      .populate("warehouse customer payments.paymentType")
      .populate({ path: "items.item" })
      .populate({ path: "items.tax", model: "Tax" })
      .populate("createdBy", "name FirstName LastName email");
    if (!updatedSale) {
      return res.status(404).json({ message: "Sale not found!" });
    }

    // Recompute creatorName if needed
    let creatorName = "";
    if (updatedSale.createdBy) {
      if (
        updatedSale.createdByModel === "Admin" &&
        updatedSale.createdBy.name
      ) {
        creatorName = updatedSale.createdBy.name;
      } else if (
        updatedSale.createdBy.FirstName &&
        updatedSale.createdBy.LastName
      ) {
        creatorName = `${updatedSale.createdBy.FirstName} ${updatedSale.createdBy.LastName}`;
      }
    }

    const processedSale = { ...updatedSale.toObject(), creatorName };
    res.status(200).json({
      message: "Sale updated successfully!",
      sale: processedSale,
    });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};

// Delete sale
exports.deleteSale = async (req, res) => {
  try {
    const sale = await Sales.findById(req.params.id);
    if (!sale) {
      return res.status(404).json({ message: "Sale not found!" });
    }
    await Sales.findByIdAndDelete(req.params.id);
    res.status(200).json({ message: "Sale deleted successfully!" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal server error" });
  }
};

exports.getRecentSalesInvoices = async (req, res) => {
  const limit = parseInt(req.query.limit) || 10;

  try {
    const recentSales = await Sales.find()
      .sort({ createdAt: -1 })
      .limit(limit)
      .populate("customer", "name phone email")
      .populate("createdBy", "name email")
      .select("invoiceId createdAt totalAmount status customer createdBy");

    return res.status(200).json({
      success: true,
      data: recentSales,
    });
  } catch (error) {
    return res.status(500).json({
      success: false,
      message: error.message,
    });
  }
};